//! 时间工具
//! 
//! 提供时间相关的通用工具函数

use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

/// 时间工具类
pub struct TimeUtils;

impl TimeUtils {
    /// 获取当前时间戳（秒）
    pub fn current_timestamp() -> u64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_secs()
    }

    /// 获取当前时间戳（毫秒）
    pub fn current_timestamp_millis() -> u64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_millis() as u64
    }

    /// 获取当前时间戳（微秒）
    pub fn current_timestamp_micros() -> u64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_default()
            .as_micros() as u64
    }

    /// 将时间戳转换为 SystemTime
    pub fn timestamp_to_system_time(timestamp: u64) -> SystemTime {
        UNIX_EPOCH + Duration::from_secs(timestamp)
    }

    /// 计算两个时间点之间的持续时间
    pub fn duration_between(start: SystemTime, end: SystemTime) -> Duration {
        end.duration_since(start).unwrap_or_default()
    }

    /// 格式化持续时间为人类可读格式
    pub fn format_duration(duration: Duration) -> String {
        let total_seconds = duration.as_secs();
        let days = total_seconds / 86400;
        let hours = (total_seconds % 86400) / 3600;
        let minutes = (total_seconds % 3600) / 60;
        let seconds = total_seconds % 60;
        let millis = duration.subsec_millis();

        if days > 0 {
            format!("{days}d {hours}h {minutes}m {seconds}s")
        } else if hours > 0 {
            format!("{hours}h {minutes}m {seconds}s")
        } else if minutes > 0 {
            format!("{minutes}m {seconds}s")
        } else if seconds > 0 {
            format!("{}.{}s", seconds, millis / 100)
        } else {
            format!("{millis}ms")
        }
    }

    /// 休眠指定毫秒数
    pub fn sleep_millis(millis: u64) {
        std::thread::sleep(Duration::from_millis(millis));
    }

    /// 休眠指定微秒数
    pub fn sleep_micros(micros: u64) {
        std::thread::sleep(Duration::from_micros(micros));
    }
}

/// 性能计时器
#[derive(Debug)]
pub struct Timer {
    start: Instant,
    name: String,
}

impl Timer {
    /// 创建新的计时器
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            start: Instant::now(),
            name: name.into(),
        }
    }

    /// 获取已经过的时间
    pub fn elapsed(&self) -> Duration {
        self.start.elapsed()
    }

    /// 获取已经过的毫秒数
    pub fn elapsed_millis(&self) -> u64 {
        self.elapsed().as_millis() as u64
    }

    /// 获取已经过的微秒数
    pub fn elapsed_micros(&self) -> u64 {
        self.elapsed().as_micros() as u64
    }

    /// 重置计时器
    pub fn reset(&mut self) {
        self.start = Instant::now();
    }

    /// 停止计时器并打印结果
    pub fn stop_and_print(self) {
        println!("{}: {}", self.name, TimeUtils::format_duration(self.elapsed()));
    }
}

/// 简单的性能基准测试工具
pub struct Benchmark;

impl Benchmark {
    /// 执行基准测试
    pub fn run<F>(name: &str, iterations: usize, mut f: F) -> Duration
    where
        F: FnMut(),
    {
        let timer = Timer::new(format!("{name} ({iterations}x)"));
        
        for _ in 0..iterations {
            f();
        }
        
        let elapsed = timer.elapsed();
        let avg_per_op = elapsed / iterations as u32;
        
        println!("{}: 总耗时 {}, 平均 {}/op, {:.0} ops/秒", 
                name, 
                TimeUtils::format_duration(elapsed),
                TimeUtils::format_duration(avg_per_op),
                iterations as f64 / elapsed.as_secs_f64());
        
        elapsed
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_timestamps() {
        let ts1 = TimeUtils::current_timestamp();
        let ts2 = TimeUtils::current_timestamp_millis();
        let ts3 = TimeUtils::current_timestamp_micros();
        
        assert!(ts1 > 0);
        assert!(ts2 > ts1 * 1000);
        assert!(ts3 > ts2 * 1000);
    }

    #[test]
    fn test_timer() {
        let mut timer = Timer::new("test");
        
        TimeUtils::sleep_millis(10);
        
        let elapsed = timer.elapsed_millis();
        assert!(elapsed >= 10);
        
        timer.reset();
        let new_elapsed = timer.elapsed_millis();
        assert!(new_elapsed < elapsed);
    }

    #[test]
    fn test_format_duration() {
        let duration = Duration::from_millis(1500);
        let formatted = TimeUtils::format_duration(duration);
        assert!(formatted.contains("1.5s"));
        
        let duration = Duration::from_secs(65);
        let formatted = TimeUtils::format_duration(duration);
        assert!(formatted.contains("1m 5s"));
    }
}